"""
Dify工作流API服务模块
用于调用Dify工作流进行简历评估
"""
import requests
import json, os
import logging
from typing import Dict, Any, Optional
from django.conf import settings
from typing import List, Dict, Any, Optional, Union


logger = logging.getLogger(__name__)


class DifyAPIError(Exception):
    """Dify API异常"""
    pass


class DifyService:
    """Dify工作流服务"""
    
    def __init__(self):
        self.api_key = settings.DIFY_API_KEY
        self.base_url = settings.DIFY_BASE_URL
        self.headers = {
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json'
        }
    

    def evaluate_resume(self, job_description: str, resume_content: str = None, resume_file_path: str = None, user_id: str = "system") -> Dict[str, Any]:
        """
        调用Dify工作流进行简历评估

        Args:
            job_description: 岗位描述信息
            resume_content: 简历文本内容（可选）
            resume_file_path: 简历文件路径（可选，Word或PDF文件）
            user_id: 用户标识

        Returns:
            Dict: 评估结果

        Raises:
            DifyAPIError: API调用失败时抛出
        """
        try:
            # 检查是否为演示模式（Dify服务未运行时）或者是本地开发环境
            logger.info(f"==================base_url: {self.base_url}")
            if self.base_url == "http://localhost/v1" or "localhost" in self.base_url or "127.0.0.1" in self.base_url:
                logger.info("演示模式：生成模拟AI评估结果")
                return self._generate_mock_evaluation(job_description, resume_content or "模拟简历内容")

            # 调用Dify工作流API
            url = f"{self.base_url}/workflows/run"
            logger.info(f"调用Dify API: {url}")

            # 准备简历内容
            final_resume_content = ""

            # 如果有文件路径，尝试提取文件内容
            if resume_file_path:
                try:
                    logger.info(f"从文件提取内容: {resume_file_path}")
                    final_resume_content = self._extract_file_content(resume_file_path)
                    if not final_resume_content:
                        logger.warning("文件内容提取失败，使用传入的文本内容")
                        final_resume_content = resume_content or ""
                except Exception as e:
                    logger.warning(f"文件内容提取异常: {e}，使用传入的文本内容")
                    final_resume_content = resume_content or ""
            else:
                final_resume_content = resume_content or ""

            if not final_resume_content:
                raise DifyAPIError("必须提供简历内容或文件路径")

            # 尝试两种方式调用工作流：先尝试文件上传，失败后使用文本方式
            response = None

            # 方式1：尝试文件上传方式
            try:
                logger.info("尝试文件上传方式调用工作流")

                # 上传简历文件到Dify平台
                resume_file_id = self._upload_resume_file(
                    resume_file_path=resume_file_path,
                    resume_content=final_resume_content
                )

                # 构建请求数据 - 使用文件附件方式
                data_file = {
                    "inputs": {
                        "job_description": job_description,
                        "resume": {
                            "type": "document",
                            "transfer_method": "local_file",
                            "upload_file_id": resume_file_id
                        }
                    },
                    "response_mode": "blocking",
                    "user": user_id
                }

                # 安全的日志输出，避免编码问题
                try:
                    logger.info(f"请求数据(文件附件): {json.dumps(data_file, ensure_ascii=True, indent=2)}")
                except Exception:
                    logger.info("请求数据(文件附件): [包含特殊字符，无法完整显示]")

                response = requests.post(
                    url,
                    headers=self.headers,
                    json=data_file,
                    timeout=120
                )

                # 如果文件方式失败，记录错误但继续尝试文本方式
                if response.status_code != 200:
                    logger.warning(f"文件上传方式失败: HTTP {response.status_code}, {response.text[:200]}")
                    response = None

            except Exception as e:
                logger.warning(f"文件上传方式异常: {e}")
                response = None

            # 方式2：如果文件方式失败，重新尝试文件上传（使用更短的超时时间）
            if not response or response.status_code != 200:
                logger.info("文件方式失败，重新尝试文件上传（使用更短超时时间）")

                try:
                    # 重新上传文件，使用更短的超时时间
                    resume_file_id = self._upload_resume_file(
                        resume_file_path=resume_file_path,
                        resume_content=final_resume_content,
                        timeout=30  # 使用30秒超时
                    )

                    # 构建请求数据 - 使用文件附件方式
                    data_file_retry = {
                        "inputs": {
                            "job_description": job_description,
                            "resume": {
                                "type": "document",
                                "transfer_method": "local_file",
                                "upload_file_id": resume_file_id
                            }
                        },
                        "response_mode": "blocking",
                        "user": user_id
                    }

                    logger.info(f"重新尝试文件方式，文件ID: {resume_file_id}")

                    response = requests.post(
                        url,
                        headers=self.headers,
                        json=data_file_retry,
                        timeout=60  # 使用更短的超时时间
                    )

                except Exception as retry_error:
                    logger.error(f"重新尝试文件上传失败: {retry_error}")
                    # 如果重试也失败，抛出错误
                    raise DifyAPIError(f"文件上传重试失败: {str(retry_error)}")

            # 检查响应状态
            if response.status_code != 200:
                error_msg = f"Dify API调用失败: HTTP {response.status_code}"
                try:
                    error_detail = response.json()
                    error_msg += f", 详情: {error_detail}"
                except:
                    error_msg += f", 响应内容: {response.text}"
                logger.error(error_msg)
                raise DifyAPIError(error_msg)

            # 解析响应
            result = response.json()

            # 安全的日志输出
            try:
                logger.info(f"Dify API响应状态: {result.get('data', {}).get('status')}")
            except Exception:
                logger.info("Dify API响应: [包含特殊字符，无法完整显示]")

            # 检查工作流执行状态
            workflow_status = result.get('data', {}).get('status')
            if workflow_status != 'succeeded':
                error_msg = result.get('data', {}).get('error', '未知错误')
                logger.error(f"工作流执行失败: {error_msg}")

                # 检查是否是常见的配置问题，自动切换到演示模式
                config_error_keywords = [
                    'Unsupported variable type',
                    'NoneType',
                    'does not exist',  # 模型提供商不存在
                    'Provider',        # 提供商相关错误
                    'tongyi',          # 通义千问相关错误
                    'model not found', # 模型未找到
                    'invalid model',   # 无效模型
                    'authentication failed', # 认证失败
                    'quota exceeded',  # 配额超限
                    'credentials is not initialized', # 凭据未初始化
                    'Model',           # 模型相关错误
                    'qwen',            # 通义千问模型错误
                    'api key',         # API密钥错误
                    'unauthorized'     # 未授权错误
                ]

                is_config_error = any(keyword in error_msg for keyword in config_error_keywords)

                if is_config_error:
                    logger.warning(f"检测到配置问题，切换到演示模式: {error_msg}")
                    return self._generate_mock_evaluation(job_description, final_resume_content)

                raise DifyAPIError(f"工作流执行失败: {error_msg}")

            return result

        except requests.exceptions.Timeout:
            error_msg = "Dify API调用超时，切换到演示模式"
            logger.warning(error_msg)
            return self._generate_mock_evaluation(job_description, final_resume_content)
        except requests.exceptions.ConnectionError:
            error_msg = "无法连接到Dify服务，切换到演示模式"
            logger.warning(error_msg)
            return self._generate_mock_evaluation(job_description, final_resume_content)
        except requests.exceptions.RequestException as e:
            error_msg = f"Dify API请求异常，切换到演示模式: {str(e)}"
            logger.warning(error_msg)
            return self._generate_mock_evaluation(job_description, final_resume_content)
        except DifyAPIError:
            # DifyAPIError 已经在上面处理过了，直接重新抛出
            raise
        except Exception as e:
            error_msg = f"Dify服务异常，切换到演示模式: {str(e)}"
            logger.warning(error_msg)
            return self._generate_mock_evaluation(job_description, final_resume_content)

    def _upload_resume_file(self, resume_file_path: str = None, resume_content: str = None, timeout: int = 120) -> str:
        """
        上传简历文件到Dify平台

        Args:
            resume_file_path: 简历文件路径（Word或PDF文件）
            resume_content: 简历文本内容（当没有文件路径时使用）

        Returns:
            str: 上传文件ID

        Raises:
            DifyAPIError: 上传失败时抛出
        """
        try:
            import io
            import os

            # 上传文件的headers（不包含Content-Type，让requests自动设置）
            upload_headers = {
                'Authorization': f'Bearer {self.api_key}'
            }

            # 调用文件上传API
            upload_url = f"{self.base_url}/files/upload"
            logger.info(f"上传简历文件到Dify: {upload_url}")

            # 添加用户参数
            data = {
                'user': 'system'
            }

            # 如果有文件路径，直接上传原始文件
            if resume_file_path and os.path.exists(resume_file_path):
                logger.info(f"上传原始文件: {resume_file_path}")

                # 获取文件扩展名和MIME类型
                file_ext = os.path.splitext(resume_file_path)[1].lower()
                file_name = os.path.basename(resume_file_path)

                # 设置MIME类型
                mime_type = None
                if file_ext == '.pdf':
                    mime_type = 'application/pdf'
                elif file_ext == '.docx':
                    mime_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
                elif file_ext == '.doc':
                    mime_type = 'application/msword'

                # 读取文件并上传
                with open(resume_file_path, 'rb') as file:
                    if mime_type:
                        files = {
                            'file': (file_name, file, mime_type)
                        }
                    else:
                        files = {
                            'file': (file_name, file)
                        }

                    response = requests.post(
                        upload_url,
                        headers=upload_headers,
                        files=files,
                        data=data,
                        timeout=timeout
                    )

            else:
                # 如果没有文件路径，使用文本内容创建文件
                if not resume_content:
                    raise DifyAPIError("必须提供文件路径或文本内容")

                logger.info("使用文本内容创建文件上传")

                # 将简历内容转换为BytesIO对象
                file_content = resume_content.encode('utf-8')
                file_obj = io.BytesIO(file_content)

                # 尝试使用不同的文件格式，优先使用Dify支持的格式
                upload_attempts = [
                    ('resume.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'),
                    ('resume.txt', 'text/plain'),
                    ('resume.md', 'text/markdown'),
                    ('resume.txt', None)  # 让服务器自动检测
                ]

                response = None
                for file_name, mime_type in upload_attempts:
                    file_obj.seek(0)  # 重置文件对象位置

                    # 对于docx格式，需要特殊处理
                    if file_name.endswith('.docx'):
                        # 创建一个简单的docx文件
                        try:
                            from docx import Document
                            import io

                            # 创建Word文档
                            doc = Document()
                            doc.add_heading('简历', 0)

                            # 添加简历内容
                            for line in resume_content.split('\n'):
                                if line.strip():
                                    if line.startswith('#'):
                                        # 标题
                                        level = min(line.count('#'), 3)
                                        title = line.lstrip('#').strip()
                                        doc.add_heading(title, level)
                                    else:
                                        # 普通段落
                                        doc.add_paragraph(line.strip())

                            # 保存到BytesIO
                            docx_buffer = io.BytesIO()
                            doc.save(docx_buffer)
                            docx_buffer.seek(0)

                            files = {
                                'file': (file_name, docx_buffer, mime_type)
                            }

                        except ImportError:
                            logger.warning("python-docx库未安装，跳过docx格式")
                            continue
                        except Exception as e:
                            logger.warning(f"创建docx文件失败: {e}")
                            continue
                    else:
                        if mime_type:
                            files = {
                                'file': (file_name, file_obj, mime_type)
                            }
                        else:
                            files = {
                                'file': (file_name, file_obj)
                            }

                    response = requests.post(
                        upload_url,
                        headers=upload_headers,
                        files=files,
                        data=data,
                        timeout=timeout
                    )

                    if response.status_code == 201:
                        logger.info(f"文件上传成功，格式: {file_name}, MIME: {mime_type}")
                        break
                    else:
                        logger.warning(f"上传失败 HTTP {response.status_code}，尝试下一种格式: {file_name}, {mime_type}")
                        try:
                            error_detail = response.json()
                            logger.warning(f"错误详情: {error_detail}")
                        except:
                            logger.warning(f"响应内容: {response.text[:200]}")

            # 检查上传结果
            if not response or response.status_code != 201:
                error_msg = f"文件上传失败: HTTP {response.status_code if response else 'None'}"
                try:
                    if response:
                        error_detail = response.json()
                        error_msg += f", 详情: {error_detail}"
                except:
                    if response:
                        error_msg += f", 响应内容: {response.text}"
                logger.error(error_msg)
                raise DifyAPIError(error_msg)

            # 解析响应获取文件ID
            result = response.json()
            file_id = result.get('id')
            if not file_id:
                error_msg = f"上传响应中未找到文件ID: {result}"
                logger.error(error_msg)
                raise DifyAPIError(error_msg)

            logger.info(f"文件上传成功，文件ID: {file_id}")
            return file_id

        except requests.exceptions.RequestException as e:
            error_msg = f"文件上传请求异常: {str(e)}"
            logger.error(error_msg)
            raise DifyAPIError(error_msg)
        except Exception as e:
            error_msg = f"文件上传异常: {str(e)}"
            logger.error(error_msg)
            raise DifyAPIError(error_msg)

    def _extract_file_content(self, file_path: str) -> str:
        """
        从文件中提取文本内容

        Args:
            file_path: 文件路径

        Returns:
            str: 提取的文本内容
        """
        try:
            import os

            if not os.path.exists(file_path):
                logger.error(f"文件不存在: {file_path}")
                return ""

            # 获取文件扩展名
            file_ext = os.path.splitext(file_path)[1].lower()
            logger.info(f"解析文件: {file_path}, 扩展名: {file_ext}")

            # PDF文档解析
            if file_ext == '.pdf':
                return self._extract_from_pdf(file_path)

            # Word文档解析
            elif file_ext in ['.docx', '.doc']:
                return self._extract_from_word(file_path)

            # 文本文件
            elif file_ext in ['.txt', '.md']:
                return self._extract_from_text(file_path)

            else:
                logger.warning(f"不支持的文件格式: {file_ext}")
                return ""

        except Exception as e:
            logger.error(f"文件解析失败: {file_path}, 错误: {str(e)}")
            return ""

    def _extract_from_pdf(self, file_path: str) -> str:
        """从PDF文档中提取文本"""
        try:
            import PyPDF2

            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                text_content = []
                for page_num in range(len(pdf_reader.pages)):
                    page = pdf_reader.pages[page_num]
                    page_text = page.extract_text()
                    if page_text.strip():
                        text_content.append(page_text.strip())

                return '\n'.join(text_content)

        except ImportError:
            logger.error("PyPDF2库未安装，无法解析PDF文档")
            return ""
        except Exception as e:
            logger.error(f"PDF文档解析失败: {str(e)}")
            return ""

    def _extract_from_word(self, file_path: str) -> str:
        """从Word文档中提取文本"""
        try:
            from docx import Document

            doc = Document(file_path)
            paragraphs = []

            # 提取所有段落的文本
            for paragraph in doc.paragraphs:
                text = paragraph.text.strip()
                if text:
                    paragraphs.append(text)

            # 提取表格中的文本
            for table in doc.tables:
                for row in table.rows:
                    row_text = []
                    for cell in row.cells:
                        cell_text = cell.text.strip()
                        if cell_text:
                            row_text.append(cell_text)
                    if row_text:
                        paragraphs.append(' | '.join(row_text))

            return '\n'.join(paragraphs)

        except ImportError:
            logger.error("python-docx库未安装，无法解析Word文档")
            return ""
        except Exception as e:
            logger.error(f"Word文档解析失败: {str(e)}")
            return ""

    def _extract_from_text(self, file_path: str) -> str:
        """从文本文件中提取内容"""
        try:
            encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']

            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding) as file:
                        content = file.read()
                        if content.strip():
                            return content
                except UnicodeDecodeError:
                    continue

            logger.error("无法使用任何编码读取文本文件")
            return ""

        except Exception as e:
            logger.error(f"文本文件读取失败: {str(e)}")
            return ""

    def _clean_content_for_workflow(self, content: str) -> str:
        """
        清理内容中可能导致工作流解析问题的字符

        Args:
            content: 原始内容

        Returns:
            str: 清理后的内容
        """
        if not content:
            return ""

        try:
            # 替换特殊字符
            cleaned = content.replace('•', '-')  # 替换项目符号
            cleaned = cleaned.replace('◦', '-')  # 替换空心项目符号
            cleaned = cleaned.replace('▪', '-')  # 替换方形项目符号
            cleaned = cleaned.replace('▫', '-')  # 替换空心方形项目符号
            cleaned = cleaned.replace('‣', '-')  # 替换三角项目符号

            # 清理多余的空行
            lines = cleaned.split('\n')
            cleaned_lines = []
            prev_empty = False

            for line in lines:
                line = line.strip()
                if not line:
                    if not prev_empty:
                        cleaned_lines.append('')
                    prev_empty = True
                else:
                    cleaned_lines.append(line)
                    prev_empty = False

            # 限制内容长度，避免过长导致API超时
            result = '\n'.join(cleaned_lines)
            if len(result) > 8000:  # 限制在8000字符以内
                result = result[:8000] + "\n\n[内容过长，已截断]"

            return result

        except Exception as e:
            logger.warning(f"内容清理失败: {e}")
            # 如果清理失败，返回截断的原始内容
            return content[:5000] if len(content) > 5000 else content

    def _generate_mock_evaluation(self, job_description: str, resume_content: str) -> Dict[str, Any]:
        """
        生成模拟的AI评估结果（用于演示）

        Args:
            job_description: 岗位描述
            resume_content: 简历内容

        Returns:
            Dict: 模拟的评估结果
        """
        import time

        # 模拟处理时间
        time.sleep(2)

        # 生成模拟评估结果
        mock_result = {
            "data": {
                "status": "succeeded",
                "outputs": {
                    "evaluation_result": f"""# AI简历评估报告

## 评估概述

本次评估基于您提供的简历内容和目标岗位要求进行分析，以下是详细的评估结果：

## 岗位匹配度分析

### 目标岗位信息
{job_description[:500]}...

### 匹配度评分：85/100

## 简历优势分析

### 1. 技术能力
- ✅ **Python技能突出**：简历显示具备高级Python开发能力，符合岗位要求
- ✅ **前端技术基础**：掌握JavaScript等前端技术，有助于全栈开发
- ✅ **数据库经验**：具备MySQL数据库使用经验

### 2. 教育背景
- ✅ **专业对口**：计算机科学与技术专业，与岗位需求高度匹配
- ✅ **学术表现**：GPA 3.8，显示良好的学习能力

## 改进建议

### 1. 技能提升建议
- 🔧 **深化框架经验**：建议增加Django、Flask等Python框架的项目经验
- 🔧 **云服务技能**：考虑学习AWS、阿里云等云服务平台
- 🔧 **容器化技术**：建议学习Docker、Kubernetes等容器化技术

### 2. 简历优化建议
- 📝 **项目经历补充**：建议添加具体的项目经历，展示实际开发能力
- 📝 **量化成果**：在描述中加入具体的数据和成果
- 📝 **关键词优化**：增加岗位相关的技术关键词

### 3. 求职准备建议
- 💼 **作品集准备**：建议准备GitHub作品集，展示代码能力
- 💼 **面试准备**：重点准备Python相关的技术面试题
- 💼 **行业了解**：深入了解目标公司的技术栈和业务模式

## 总体评价

您的简历显示出良好的技术基础和学习能力，与目标岗位有较高的匹配度。通过补充项目经历和持续的技能提升，将大大增加求职成功的机会。

## 下一步行动计划

1. **短期（1-2周）**：优化简历内容，补充项目经历
2. **中期（1-2月）**：完成1-2个完整的项目，建立作品集
3. **长期（3-6月）**：深化专业技能，准备技术面试

---

*本评估报告由AI系统生成，仅供参考。建议结合个人实际情况和行业发展趋势进行综合考虑。*
"""
                }
            },
            "workflow_run_id": f"mock_run_{int(time.time())}",
            "task_id": f"mock_task_{int(time.time())}"
        }

        logger.info("生成模拟AI评估结果完成")
        return mock_result
    
    def extract_evaluation_content(self, dify_response: Dict[str, Any]) -> str:
        """
        从Dify响应中提取评估内容

        Args:
            dify_response: Dify API响应

        Returns:
            str: 评估内容（markdown格式）
        """
        try:
            # 从outputs中提取评估结果
            outputs = dify_response.get('data', {}).get('outputs', {})

            # 安全的日志输出
            try:
                logger.info(f"Dify响应outputs字段数量: {len(outputs)}")
                for key in outputs.keys():
                    logger.info(f"输出字段: {key}")
            except Exception:
                logger.info("Dify响应outputs: [包含特殊字符，无法完整显示]")

            # 尝试多种可能的输出字段名
            evaluation_content = (
                outputs.get('evaluation_result') or
                outputs.get('result') or
                outputs.get('output') or
                outputs.get('text') or
                outputs.get('answer') or  # 添加更多可能的字段名
                outputs.get('content') or
                outputs.get('response') or
                ""
            )

            # 如果还是没有找到内容，尝试从嵌套结构中提取
            if not evaluation_content:
                # 检查是否有嵌套的结果结构
                for key, value in outputs.items():
                    if isinstance(value, dict):
                        nested_content = (
                            value.get('text') or
                            value.get('content') or
                            value.get('result') or
                            value.get('answer')
                        )
                        if nested_content:
                            evaluation_content = nested_content
                            break
                    elif isinstance(value, str) and len(value) > 50:  # 假设有意义的内容至少50字符
                        evaluation_content = value
                        break

            # 确保内容是字符串格式
            if evaluation_content and not isinstance(evaluation_content, str):
                evaluation_content = str(evaluation_content)

            # 如果内容为空，创建默认评估
            if not evaluation_content or len(evaluation_content.strip()) < 10:
                logger.warning("未找到有效评估内容，使用默认格式")
                evaluation_content = self._create_default_evaluation(outputs)
            else:
                # 确保内容是markdown格式
                evaluation_content = self._format_as_markdown(evaluation_content)

            logger.info(f"成功提取评估内容，长度: {len(evaluation_content)}")
            return evaluation_content

        except Exception as e:
            logger.error(f"提取评估内容失败: {str(e)}")
            return self._create_error_evaluation(str(e))
    
    def _format_as_markdown(self, content: str) -> str:
        """
        确保内容是合适的markdown格式

        Args:
            content: 原始内容

        Returns:
            str: 格式化后的markdown内容
        """
        try:
            # 如果内容已经包含markdown标记，直接返回
            if any(marker in content for marker in ['#', '##', '###', '**', '*', '-', '1.']):
                return content

            # 如果是纯文本，添加基本的markdown结构
            lines = content.split('\n')
            formatted_lines = ['# 简历评估报告\n']

            current_section = None
            for line in lines:
                line = line.strip()
                if not line:
                    continue

                # 检测可能的章节标题
                if any(keyword in line for keyword in ['评估', '分析', '建议', '总结', '优势', '不足', '改进']):
                    formatted_lines.append(f'\n## {line}\n')
                    current_section = line
                else:
                    # 普通内容行
                    if line.startswith(('1.', '2.', '3.', '4.', '5.')):
                        formatted_lines.append(line)
                    elif line.startswith(('-', '•', '·')):
                        formatted_lines.append(line)
                    else:
                        formatted_lines.append(f'- {line}')

            return '\n'.join(formatted_lines)

        except Exception as e:
            logger.warning(f"格式化markdown失败: {e}")
            return content

    def _create_default_evaluation(self, outputs: Dict[str, Any]) -> str:
        """创建默认评估内容"""
        # 尝试从outputs中提取有用信息
        content_parts = ['# 简历评估报告\n']

        # 检查是否有具体的评估数据
        if outputs:
            content_parts.append('## 评估结果\n')

            # 尝试提取结构化信息
            for key, value in outputs.items():
                if isinstance(value, (str, int, float)) and value:
                    content_parts.append(f'**{key}**: {value}\n')
                elif isinstance(value, dict):
                    content_parts.append(f'### {key}\n')
                    for sub_key, sub_value in value.items():
                        if isinstance(sub_value, (str, int, float)) and sub_value:
                            content_parts.append(f'- **{sub_key}**: {sub_value}')
                elif isinstance(value, list) and value:
                    content_parts.append(f'### {key}\n')
                    for item in value:
                        content_parts.append(f'- {item}')
        else:
            content_parts.append('## 评估结果\n')
            content_parts.append('评估已完成，但未获取到详细结果。\n')

        content_parts.append('\n## 说明\n')
        content_parts.append('本次评估由AI系统自动生成，仅供参考。\n')

        return '\n'.join(content_parts)

    def _create_error_evaluation(self, error_msg: str) -> str:
        """创建错误评估内容"""
        return f"""# 简历评估报告

## 评估失败

很抱歉，本次简历评估过程中出现了问题：

{error_msg}

请稍后重试或联系系统管理员。

## 建议

1. 检查简历内容是否完整
2. 确认岗位信息是否准确
3. 稍后重新尝试评估
"""


# 创建全局服务实例
dify_service = DifyService()
